#!/usr/bin/env python3
"""Quick smoke test for the translate_chibicc binary.

This script generates a Cargo project from a sample C source and runs
`cargo build` to ensure the emitted crate compiles successfully.

Usage:
    python translator_smoke.py [--translator PATH] [sample.c]
"""

from __future__ import annotations

import argparse
import os
import shutil
import subprocess
import sys
import tempfile
from pathlib import Path

THIS_DIR = Path(__file__).resolve().parent
REPO_ROOT = THIS_DIR.parent


def is_windows():
    return os.name == "nt"


def exe_name(name: str) -> str:
    return name + (".exe" if is_windows() else "")


def run(cmd, cwd=None, env=None, check=True, capture=True):
    print(f"[run] {cmd} (cwd={cwd})")
    result = subprocess.run(
        cmd,
        cwd=cwd,
        env=env,
        shell=False,
        check=False,
        stdout=subprocess.PIPE if capture else None,
        stderr=subprocess.STDOUT if capture else None,
        text=True,
    )
    if capture:
        print(result.stdout)
    if check and result.returncode != 0:
        raise SystemExit(f"Command failed ({result.returncode}): {' '.join(cmd)}")
    return result


def guess_translator() -> Path:
    candidates = [
        REPO_ROOT / "src" / exe_name("translate_chibicc"),
        REPO_ROOT / exe_name("translate_chibicc"),
        REPO_ROOT / "build" / exe_name("translate_chibicc"),
        REPO_ROOT / "bin" / exe_name("translate_chibicc"),
    ]
    for c in candidates:
        if c.exists():
            return c
    raise FileNotFoundError(
        "找不到 translator 可执行文件。请先构建：\n"
        "  1) 确认已在 translate_chibicc/src 下成功编译生成 translate_chibicc(.exe)\n"
        "  2) 或用 --translator 指定路径"
    )


def ensure_cargo(optional: bool = False) -> bool:
    try:
        run(["cargo", "--version"], check=True)
        return True
    except Exception:
        if optional:
            print("[warn] 未检测到 cargo，跳过 cargo 构建阶段。")
            return False
        raise SystemExit("未检测到 cargo，请安装 Rust 工具链并将 cargo 加入 PATH。")

HELLO_C = r"""
#include <stdio.h>

int main(int argc, char** argv) {
    printf("hello from C, argc=%d\n", argc);
    for (int i = 0; i < argc; i++) {
        printf("arg[%d]=%s\n", i, argv[i]);
    }
    return 0;
}
""".lstrip()


def main():
    ap = argparse.ArgumentParser(description="translate_chibicc 冒烟测试")
    ap.add_argument("--translator", type=Path, default=None, help="translator 可执行文件路径")
    ap.add_argument("--keep", action="store_true", help="保留临时目录以便排查问题")
    ap.add_argument("--skip-cargo", action="store_true", help="未安装 cargo 时跳过构建，仅验证输出结构")
    ap.add_argument("--crate-name", default="smoke_crate", help="生成的 crate 名称")
    args = ap.parse_args()

    translator = args.translator or guess_translator()
    if not translator.exists():
        raise SystemExit(f"translator 不存在: {translator}")

    has_cargo = ensure_cargo(optional=args.skip_cargo)

    tmp = tempfile.mkdtemp(prefix="translate_chibicc_smoke_")
    tmpdir = Path(tmp)
    sample_c = tmpdir / "hello.c"
    out_dir = tmpdir / "out"
    sample_c.write_text(HELLO_C, encoding="utf-8")

    print(f"[info] 临时目录: {tmpdir}")
    print(f"[info] 生成输出目录: {out_dir}")

    # 运行 translator 生成 Cargo 工程
    cmd = [
        str(translator),
        "-o", str(out_dir),
        "--crate-name", args.crate_name,
        str(sample_c),
    ]
    run(cmd, cwd=REPO_ROOT)

    # 校验工程文件
    cargo_toml = out_dir / "Cargo.toml"
    main_rs = out_dir / "src" / "main.rs"
    build_rs = out_dir / "build.rs"
    for p in [cargo_toml, main_rs, build_rs]:
        if not p.exists():
            raise SystemExit(f"缺少生成文件: {p}")
    print("[ok] 工程脚手架生成完毕")

    # 构建
    if has_cargo:
        run(["cargo", "build", "--release"], cwd=out_dir)

    # 运行生成的可执行文件
    if has_cargo:
        bin_path = out_dir / "target" / "release" / exe_name(args.crate_name)
        if not bin_path.exists():
            # 某些平台可能是 debug 构建或名称差异，作为兜底尝试 debug
            debug_bin = out_dir / "target" / "debug" / exe_name(args.crate_name)
            if debug_bin.exists():
                bin_path = debug_bin
        if not bin_path.exists():
            raise SystemExit(f"找不到可执行文件: {bin_path}")

        r = run([str(bin_path), "foo", "bar"], cwd=out_dir)
        out = r.stdout or ""
        if "hello from C" in out and "argc=" in out:
            print("[ok] 运行成功，输出验证通过")
        else:
            print(out)
            raise SystemExit("运行输出未匹配预期")

    print(f"[success] 冒烟测试完成。输出位于: {out_dir}")
    if not args.keep:
        try:
            shutil.rmtree(tmpdir)
        except Exception:
            print(f"[warn] 清理失败，请手动删除: {tmpdir}")


if __name__ == "__main__":
    main()
